package com.ning.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.ning.reggie.common.BaseContext;
import com.ning.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 登录检查过滤器。
 * 此过滤器用于检查用户是否已经完成登录。
 */
@Slf4j // Lombok 注解，为这个类添加日志对象 log，方便输出日志信息。
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*") // 注解声明这是一个 Servlet 过滤器，过滤器名称为"loginCheckFilter"，拦截所有请求（"/*"表示拦截所有路径）。
public class LoginCheckFilter implements Filter {


    /**
     * 初始化方法，在过滤器实例化后被调用。
     *
     * @param filterConfig 过滤器配置对象。
     * @throws ServletException 如果在初始化过程中发生 Servlet 异常。
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 可以在此方法中进行一些初始化操作，目前为空实现。
    }

    //路径匹配器，支持通配符
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    /**
     * 过滤方法，实际执行过滤逻辑的地方。
     *
     * @param servletRequest  Servlet 请求对象。
     * @param servletResponse Servlet 响应对象。
     * @param filterChain     过滤器链，用于将请求传递给下一个过滤器或目标资源。
     * @throws IOException      如果在处理请求或响应时发生 I/O 错误。
     * @throws ServletException 如果在处理请求或响应时发生 Servlet 异常。
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 1、获取本次请求的 URI。
        String requestURI = request.getRequestURI();// /backend/index.html
        log.info("拦截到请求：{}", requestURI);

        // 定义不需要处理的请求路径。
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**",
                "/common/**",
                "/user/sendMsg",
                "/user/login",
                "/doc.html",
                "/webjars/**",
                "/swagger-resources",
                "/v2/api-docs"
        };

        // 2、判断本次请求是否需要处理。
        boolean check = check(urls, requestURI);

        // 3、如果不需要处理，则直接放行。
        if (check) {
            log.info("本次请求{}不需要处理", requestURI);
            filterChain.doFilter(request, response);
            return;
        }


        //4-1、判断登录状态，如果已登录，则直接放行
        if (request.getSession().getAttribute("employee")!= null) {
            // 如果 session 中存在名为 "employee" 的属性，说明员工已登录，打印日志记录登录员工的 id。
            log.info("用户已登录，用户 id 为：{}", request.getSession().getAttribute("employee"));
            // 将 session 中的员工 id 转换为 Long 类型，并设置到 BaseContext 中，方便后续在代码中获取当前登录用户的 id。
            Long empId = (Long) request.getSession().getAttribute("employee");
            BaseContext.setCurrentId(empId);
            // 放行请求，让请求继续向后传递，进入下一个过滤器或到达目标资源。
            filterChain.doFilter(request, response);
            return;
        }

        //4-2、判断登录状态，如果已登录，则直接放行
        if (request.getSession().getAttribute("user")!= null) {
            // 如果 session 中存在名为 "user" 的属性，说明普通用户已登录，打印日志记录登录用户的 id。
            log.info("用户已登录，用户 id 为：{}", request.getSession().getAttribute("user"));
            // 将 session 中的用户 id 转换为 Long 类型，并设置到 BaseContext 中，方便后续在代码中获取当前登录用户的 id。
            Long userId = (Long) request.getSession().getAttribute("user");
            BaseContext.setCurrentId(userId);
            // 放行请求，让请求继续向后传递，进入下一个过滤器或到达目标资源。
            filterChain.doFilter(request, response);
            return;
        }

        log.info("用户未登录");
        // 5、如果未登录则返回未登录结果，通过输出流方式向客户端页面响应数据。
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
        return;

    }

    /**
     * 路径匹配，检查本次请求是否需要放行。
     *
     * @param urls      不需要处理的请求路径数组。
     * @param requestURI 当前请求的 URI。
     * @return 如果当前请求的 URI 与数组中的某个路径匹配，则返回 true，表示不需要处理；否则返回 false。
     */
    public boolean check(String[] urls, String requestURI) {
        for (String url : urls) {
            boolean match = PATH_MATCHER.match(url, requestURI);
            if (match) {
                return true;
            }
        }
        return false;
    }

    /**
     * 销毁方法，在过滤器被销毁之前被调用。
     */
    @Override
    public void destroy() {
        // 可以在此方法中进行一些清理操作，目前为空实现。
    }
}